#include <iostream>
#include <cstdlib>

#include <memory>// 包含 unique_ptr 头文件

/*
    GC---垃圾回收机制
*/

// 定义了两个类 Car 和 Person，并演示了它们之间的相互引用

class Person;// 前置申明
class Car
{
public:
    Car()
    {
        std::cout << "Car" << std::endl;
    }

    ~Car()
    {
        std::cout << "~Car()" << std::endl;
    }

public:
    // 智能指针，管理 Person 对象的生命周期，初始值为 nullptr。
    std::shared_ptr<Person> m_person = nullptr;
};

class Person
{
public:
    Person()
    {
        std::cout << "Person" << std::endl;
    }

    Person(int age):m_age(age)
    {
        std::cout << "Person(int age)" << std::endl;
    }

    ~Person()
    {
        std::cout << "~Person()" << std::endl;
    }

public:
    // 成员函数尽量 单独在另一个 public 中
    void run()
    {
        std::cout << "run()" << std::endl;
    }

public:
    // 智能指针，管理 Car 对象的生命周期，初始值为 nullptr。
    std::shared_ptr<Car> m_car = nullptr;

private:
    int m_age;
};



// 循环引用问题
// 使用 std::shared_ptr 管理 Car 和 Person 对象的生命周期时，会遇到循环引用的问题。即 Car 和 Person 对象相互持有对方的 std::shared_ptr，导致引用计数无法归零，进而导致内存泄漏。
// 解决方案
// 使用 std::weak_ptr 可以打破循环引用。std::weak_ptr 不增加引用计数，允许智能指针引用对象但不控制其生命周期。
// 修改后
#if 0
class Person; // 前置声明
class Car
{
public:
    Car()
    {
        std::cout << "Car" << std::endl;
    }

    ~Car()
    {
        std::cout << "~Car()" << std::endl;
    }

public:
    std::weak_ptr<Person> m_person; // 使用 weak_ptr
};

class Person
{
public:
    Person()
    {
        std::cout << "Person" << std::endl;
    }

    Person(int age):m_age(age)
    {
        std::cout << "Person(int age)" << std::endl;
    }

    ~Person()
    {
        std::cout << "~Person()" << std::endl;
    }

public:
    void run()
    {
        std::cout << "run()" << std::endl;
    }

public:
    std::shared_ptr<Car> m_car = nullptr;

private:
    int m_age;
};


#endif

int main(int argc, char *argv[])
{
#if 0
    // 多个 shared_ptr 可以指向 同一个对象，当最后一个shared_ptr 在作用域范围内结束时，对象 才会被自动释放
    {
        std::shared_ptr<Person> p2;// 声明一个空的 shared_ptr，初始值为 nullptr
        std::cout << "111" << std::endl;
        {
            std::shared_ptr<Person> p1(new Person(30));// 创建一个新的 Person 对象，shared_ptr p1 管理这个对象。输出 "Person(int age)"，因为调用了带参数的构造函数
            p1->run();
            std::cout << "cnt" << p1.use_count() << std::endl; // 输出 p1 的引用计数，use_count 返回 1

            p2 = p1;
            std::cout << "cnt:" << p2.use_count() << std::endl; // 将 p1 赋值给 p2，现在 p2 也指向同一个 Person 对象。此时，p1 和 p2 都指向同一个对象，引用计数增加到 2
        }// 第二级作用域结束时，p1 离开作用域，析构函数调用，引用计数减少到 1
        std::cout << "cnt:" << p2.use_count() << std::endl;     // 1
        std::cout << "222" << std::endl;
    }// 第一级作用域结束时，p2 离开作用域，析构函数调用，引用计数减少到 0，Person 对象被销毁。输出 "~Person()"。
    std::cout << "333" << std::endl;

    // shared_ptr 解决了 auto_ptr 遗留的 动态分配数组 问题
    // 创建一个 std::shared_ptr，用于管理 Person 对象数组。
    // 动态分配一个包含 5 个 Person 对象的数组，并使用默认构造函数初始化每个对象。
    std::shared_ptr<Person[]> person(new Person[5]{});
    /* 数组使用 */
    // 访问数组中的第三个元素（索引从0开始）
    // std::shared_ptr 支持 operator[]，这使得访问数组元素变得简单和直观
    person[2].run();
#endif
#if 0
    // 等价于 Person * arr = new Person[5]{};
    //       delete [] arr;
#endif

    // 使用 std::shared_ptr 创建两个类 Person 和 Car 的对象
    std::shared_ptr<Person> person(new Person);
    std::shared_ptr<Car> car(new Car);

    // 设置它们之间的相互引用
    person->m_car = car;// 将 car 赋值给 person 的成员变量 m_car
    car->m_person = person;// 将 person 赋值给 car 的成员变量 m_person

    // 相互引用和引用计数
    // 此时，person 和 car 的引用计数分别为 2，因为：
            // person 被 shared_ptr 对象 person 和 car->m_person 持有。
            // car 被 shared_ptr 对象 car 和 person->m_car 持有。
            // 这会引发循环引用的问题，即 Person 和 Car 对象无法被正确销毁，因为它们的引用计数永远不会变为 0
    // 解决循环引用
    // 为了解决循环引用问题，我们可以将 Car 中指向 Person 的指针改为 std::weak_ptr，这样 Car 对 Person 的引用不会增加 Person 对象的引用计数

    return 0;
}